package cn.pomelo.secondskill.service.impl;

import cn.hutool.core.lang.ObjectId;
import cn.pomelo.secondskill.common.Constants;
import cn.pomelo.secondskill.exception.SecondsKillException;
import cn.pomelo.secondskill.model.*;
import cn.pomelo.secondskill.rabbitMQ.Subscriber;
import cn.pomelo.secondskill.service.AddressService;
import cn.pomelo.secondskill.service.GoodsService;
import cn.pomelo.secondskill.service.OrdersService;
import cn.pomelo.secondskill.service.RedisService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class RedisServiceImpl implements RedisService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private GoodsService goodsService;

    @Resource
    private OrdersService ordersService;

    @Resource
    private AddressService addressService;

    @Resource
    private Subscriber<Orders> subscriber;

    @Override
    public List<Goods> list() {
        List<Goods> goodsList = (List<Goods>) redisTemplate.opsForValue().get(Constants.REDIS_KEY_PREFIX + ":list");
        if (goodsList == null) {
            goodsList = goodsService.findAll();
            redisTemplate.opsForValue().set(Constants.REDIS_KEY_PREFIX + ":list", goodsList, 60, TimeUnit.SECONDS);
        }
        return goodsList;
    }

    @Override
    public GoodsDetail detail(Integer id) {
        Goods detail = (Goods) redisTemplate.opsForValue().get(Constants.REDIS_KEY_PREFIX + ":goods:" + id);
        if (detail == null) { // redis 还没有该商品
            detail = goodsService.selectByPrimaryKey(id);
            if (detail == null) {
                return null;
            }
        }
        long start = detail.getKillDate().getTime();
        long end = detail.getKillDate().getTime();
        long now = new Date().getTime();
        int scState = 1, scTime = 0; // 默认秒杀进行中
        if (start > now) { // 秒杀还没有开始
            scState = 0;
            scTime = (int) (now - start) / 1000;
        } else if (end < now) { // 秒杀结束
            scState = 2;
        }
        GoodsDetail goodsDetail = new GoodsDetail();
        goodsDetail.setGoods(detail);
        goodsDetail.setScState(scState);
        goodsDetail.setScTime(scTime);
        redisTemplate.opsForValue().set(Constants.REDIS_KEY_PREFIX + ":goods:" + id, detail, 60, TimeUnit.SECONDS);
        return goodsDetail;
    }

    /**
     * 秒杀订单
     *
     * @return 秒杀订单详情
     */
    @Override
    public OrdersDetail secondsKill(Orders or) throws SecondsKillException {
        Goods goods = goodsService.selectByPrimaryKey(or.getGoodsNumber());
        if (goods == null) {
            throw new SecondsKillException("商品不存在！");
        }
        Integer quantity = goods.getQuantity();
        if (quantity <= 0) {
            throw new SecondsKillException("商品数量不足");
        }
        Orders orders = (Orders) redisTemplate.opsForValue().get(Constants.REDIS_KEY_PREFIX + ":secondsKillOrder:" + or.getUserId() + ":" + or.getGoodsNumber());
        if (orders != null) {
            throw new SecondsKillException("每个用户限购一件");
        }
        // redis 中的订单已经过期就从数据库查询 订单支付成功 待支付，支付成功修改状态
        orders = ordersService.findByUseridAndGoodsId(or.getUserId(), or.getGoodsNumber(), 1);
        if (orders != null) {
            // 如果已经找到了秒杀订单，返回错误提示，并且将这个秒杀订单保存到redis中，下次
            //这个用户再次进行秒杀这个商品的时候，就可以直接从redis中获取，而不是从数据库中查询
            redisTemplate.opsForValue().set(Constants.REDIS_KEY_PREFIX + ":secondsKillOrder:" + or.getUserId() + ":" + or.getGoodsNumber(), orders, 15, TimeUnit.MINUTES);
            throw new SecondsKillException("每个用户限购一件");
        }
        subscriber.send(Constants.SECONDS_KILL_ORDER_QUEUE,"下单成功", or);
        // 将秒杀订单存到redis
        if (or.getState() == 1) {
            redisTemplate.opsForValue().set(Constants.REDIS_KEY_PREFIX + ":secondsKillOrder:" + or.getUserId() + ":" + or.getGoodsNumber(), or, 15, TimeUnit.MINUTES);
        }
        OrdersDetail ordersDetail = new OrdersDetail();
        ordersDetail.setOrders(or);
        ordersDetail.setState(1);
        // 将订单状态存到redis
        redisTemplate.opsForValue().set(Constants.REDIS_KEY_PREFIX + ":killOrder:" + or.getUserId() + ":" + or.getId(), ordersDetail, 15, TimeUnit.MINUTES);
        return ordersDetail;
    }

    /**
     * 通过用户编号以及订单编号查询订单详情
     *
     * @param userid  用户id
     * @param orderId 订单id
     * @return 订单详情
     */
    @Override
    public OrdersDetail scOrderInfo(Integer userid, String orderId) {
        OrdersDetail ordersDetail = (OrdersDetail) redisTemplate.opsForValue().get(Constants.REDIS_KEY_PREFIX + ":killOrder:" + userid + ":" + orderId);
        if (ordersDetail == null) {
            // redis 已经失效，从数据库查询
            Orders orders = ordersService.selectByPrimaryKey(orderId);
            ordersDetail = new OrdersDetail();
            ordersDetail.setOrders(orders);
            ordersDetail.setState(orders.getPayTime() == null ? 0 : 1);
        }
        redisTemplate.opsForValue().set(Constants.REDIS_KEY_PREFIX + ":killOrder:" + userid + ":" + orderId, ordersDetail, 15, TimeUnit.MINUTES);
        return ordersDetail;
    }

    /**
     * 通过用户id查询订单
     *
     * @param userid 用户id
     * @return 订单情况
     */
    @Override
    public List<Orders> getOrdersByUserid(Integer userid) {
        List<Orders> ordersList = (List<Orders>) redisTemplate.opsForValue().get(Constants.REDIS_KEY_PREFIX + ":ordersList:" + userid);
        if (ordersList == null) {
            // redis 已经失效，从数据库查询
            ordersList = ordersService.findByUserId(userid);
            redisTemplate.opsForValue().set(Constants.REDIS_KEY_PREFIX + ":ordersList:" + userid, ordersList, 60, TimeUnit.SECONDS);
        }
        return ordersList;
    }


    @Override
    public Orders generate(Integer userid, Integer goodsId) throws SecondsKillException {
        Goods goods = goodsService.selectByPrimaryKey(goodsId);
        if (goods == null) {
            throw new SecondsKillException("商品不存在！");
        }
        Orders orders = new Orders();
        orders.setId(ObjectId.next());
        orders.setUserId(userid);
        orders.setGoodsNumber(goodsId);
        orders.setGoods(goods);
        Address defaultAdd = addressService.findDefaultAddByUserid(userid);
        if (defaultAdd != null) {
            orders.setAddressId(defaultAdd.getId());
            orders.setAddress(defaultAdd);
        }
        return orders;
    }
}
